package com.franklin.java.service.database.iu;

import com.franklin.java.service.database.AbstractJdbcConsole;
import com.franklin.java.utils.DocumentUtils;
import com.franklin.java.utils.EditorUtils;
import com.franklin.plugins.common.utils.DataCheckUtils;
import com.intellij.database.console.JdbcConsole;
import com.intellij.database.model.DasNamed;
import com.intellij.database.psi.DbDataSource;
import com.intellij.database.psi.DbPsiFacade;
import com.intellij.database.settings.DatabaseSettings;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.ui.popup.ListPopup;
import com.intellij.openapi.ui.popup.PopupStep;
import com.intellij.openapi.ui.popup.util.BaseListPopupStep;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.sql.script.SqlScriptModel;
import com.intellij.util.containers.JBIterable;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author Franklin
 * @since 2021/9/23 15:27
 */
class DatabaseToolJdbcConsole extends AbstractJdbcConsole {

    private JdbcConsole jdbcConsole;

    private Editor editor;


    public DatabaseToolJdbcConsole(Project project, String sql) {
        super(project, sql);

        EditorFactory editorFactory = EditorFactory.getInstance();
        Document document = editorFactory.createDocument("");
        editor = editorFactory.createEditor(document);
        EditorUtils.initEditor(editor);

        checkJdbcConsoleActive("");

    }

    private boolean checkJdbcConsoleActive(String sqlFileName) {
        List<JdbcConsole> activeConsoles = JdbcConsole.getActiveConsoles(project);
        if (DataCheckUtils.isNotEmpty(activeConsoles)) {
            if (DataCheckUtils.isEmpty(sqlFileName)) {
                this.jdbcConsole = activeConsoles.get(activeConsoles.size() - 1);
            } else {
                this.jdbcConsole = activeConsoles.stream()
                    .filter(s -> s.getVirtualFile().getName().equals(sqlFileName))
                    .findFirst()
                    .orElse(null);
            }
        }
        return Objects.nonNull(this.jdbcConsole);
    }

    @Override
    public boolean executeQuery() {
        if (Objects.isNull(this.jdbcConsole)) {
            return false;
        }
        runSql();
        return true;
    }

    @Override
    public JBPopup getDatasourceChoosingPopup() {
        DbPsiFacade dbPsiFacade = DbPsiFacade.getInstance(project);
        List<DbDataSource> dataSources = dbPsiFacade.getDataSources();

        List<String> dataSourceNames = dataSources.stream()
            .map(DasNamed::getName)
            .collect(Collectors.toList());
        List<Icon> iconList = dataSources.stream()
            .map(DbDataSource::getIcon)
            .collect(Collectors.toList());
        JBPopupFactory jbPopupFactory = JBPopupFactory.getInstance();
        ListPopup dsPopup = jbPopupFactory.createListPopup(
            new BaseListPopupStep<>(
                "Choose DataSource",
                dataSourceNames,
                iconList
            ) {
                @Override
                public @Nullable
                PopupStep<?> onChosen(String selectedValue, boolean finalChoice) {
                    for (DbDataSource dataSource : dataSources) {
                        if (dataSource.getName().equals(selectedValue)) {
                            if (!checkJdbcConsoleActive(selectedValue)) {
                                jdbcConsole = JdbcConsole
                                    .newConsole(project)
                                    .fromDataSource(dataSource)
                                    .forFile(getSqlFile(selectedValue))
                                    .build();
                            }
                            runSql();
                            break;
                        }
                    }
                    return null;
                }

            });
        return dsPopup;
    }

    private void runSql() {
        VirtualFile sqlFile = getSqlFile();

        DocumentUtils.writeSync(() -> {
            try {
                sqlFile.setBinaryContent(sql.getBytes(StandardCharsets.UTF_8));
            } catch (IOException e) {

            }
        });

        SqlScriptModel sqlScriptModel = new SqlScriptModel(project, sqlFile, null);

        this.jdbcConsole.executeQueries(editor, sqlScriptModel, new DatabaseSettings.ExecOption());
    }
}
